/**
 * File: IndexReadProcessor.java
 * Created by: mhaimel
 * Created on: 14 Jul 2009
 * CVS:  $Id: IndexReadProcessor.java,v 1.3 2009/10/09 15:14:58 mhaimel Exp $
 */
package uk.ac.ebi.curtain.processor.writer.impl;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import org.apache.commons.io.FileUtils;
import org.apache.commons.lang.time.StopWatch;

import uk.ac.ebi.curtain.util.FileIndexReader;
import uk.ac.ebi.curtain.util.FileIndexUtil;
import uk.ac.ebi.curtain.util.FileIndexReader.IndexFilter;
import uk.ac.ebi.curtain.util.FileIndexUtil.FileIndexEvent;
import uk.ac.ebi.curtain.util.impl.MultiFileFastqWriter;
import uk.ac.ebi.curtain.utils.CurtainUncheckedException;
import uk.ac.ebi.curtain.utils.file.FileInfo;
import uk.ac.ebi.curtain.utils.io.impl.FileIO;
import uk.ac.ebi.velvet.model.Strand;
import uk.ac.ebi.velvet.model.Supercontig;

/**
 * @author mhaimel
 *
 */
public class IndexReadProcessor extends AbstractSequenceProcessor<File, File> {
	private final Integer BUFFER = 100000;
//	private Set<String> contigIds = new HashSet<String>();

	@Override
	protected File buildReturnObject() {
//		BucketCollectionBean bean = new BucketCollectionBean(getInput());
//		bean.getContigs().addAll(contigIds);
		return getInput();
	}
	

	public void reset() {
//		contigIds = new HashSet<String>();
		setInput(null);
		super.reset();
	}
	
	@Override
	protected MultiFileFastqWriter _newWriter() {
//		return new MyWriter(getContext().getFileAccess());
		return new MultiFileFastqWriter(getContext().getFileAccess());
	}

	@Override
	public void process() {
		_prepareWriter(getInput());	
		_deleteFiles();
		_writeFiles(getInput());
	}

	private void _writeFiles(File baseDir) {
		File summary = Supercontig.getSummaryOutputFile(baseDir);
		getLog().debug("Prepare Bucket " + summary);
		FileIndexReader reader = null; 
		WriteBuffer wb = new WriteBuffer(BUFFER);
		StopWatch sw = new StopWatch();
		try {
			IndexFilter indexFilter = new IndexFilter();
			indexFilter.allowAll(false);
			indexFilter.allowContig(true);
			indexFilter.allowRead(true);
			reader = FileIndexUtil.buildReader(summary, wb,indexFilter);
			FileIndexUtil.registerFiles(reader, getContext().getArguments(), getContext().getGlobalFileIndex());
			reader.open();
			getWriter().openWrite(true);

			sw.start();
//			reader.readAll();
			boolean isEOF = false;
			do{
				isEOF = reader.readBlock(BUFFER);
				// flush buffer
				getWriter().addReadBatch(wb.fileArr.toArray(new Integer[0]), null,null,wb.posArr.toArray(new Long[0]));
				wb.reset();
			} while(!isEOF);
			sw.stop();
		} catch (IOException e) {
			throw new CurtainUncheckedException("Problems reading from file " + summary,e);
		} finally{
			FileIO.closeQuietly(getWriter());
			FileIO.closeQuietly(reader);
		}
		getLog().debug("Finished read/write bucket in " + sw +" to " + summary  + "!");
	}

	private void _deleteFiles() {
		for(FileInfo info : getOutFiles().keySet()){
			FileUtils.deleteQuietly(info.getFile());
		}
	}
	
	private class WriteBuffer implements FileIndexEvent {
		private final List<Integer> fileArr;
		private final List<Long> posArr;
		
		public WriteBuffer(){
			this.fileArr = new ArrayList<Integer>();
			this.posArr = new ArrayList<Long>();
		}
		
		public WriteBuffer(Integer size){
			this.fileArr = new ArrayList<Integer>(size);
			this.posArr = new ArrayList<Long>(size);
		}
		
		public void reset(){
			this.fileArr.clear();
			this.posArr.clear();
		}

		@Override
		public void addContig(FileInfo fi, String key, Long pos){/*ignore*/}
		@Override
		public void addContigPosition(FileInfo fi, Long pos){
			add(fi,pos);
		}
		private void add(FileInfo fi, Long pos){
			fileArr.add(getContext().getGlobalFileIndex().getId(fi));
			posArr.add(pos);
		}
		@Override
		public void addFile(FileInfo fi, Integer category){/*ignore*/}
		@Override
		public void addFileId(Integer fid, FileInfo fi){/*ignore*/}
		@Override
		public void addInsertLength(Integer category, Integer insLen) {/*ignore*/}
		@Override
		public void addInsertLengthSd(Integer category, Integer sd) {/*ignore*/}
		@Override
		public void addRead(FileInfo fi, String key, Strand strand, Long pos) {/*ignore*/}
		@Override
		public void addReadPosition(FileInfo fi, Strand strand, Long pos) {
			add(fi, pos);
		}
		@Override
		public void close() throws IOException {/*ignore*/}

		@Override
		public void addCategory(Integer category, String id) {/*ignore*/}
		
	}	
}
